/*
 * $Id: BaseJsonServlet.java 46 2012-02-17 12:50:01Z rook.alex@gmail.com $
 */
package ua.org.energy.vkek.site.web;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Text;
import com.google.gson.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Stack;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import ua.org.energy.vkek.site.model.BaseEntity;
import ua.org.energy.vkek.site.model.BaseEntity.EntityPathElement;

public abstract class BaseJsonServlet extends HttpServlet {

    final int MAX_JSON_CONTENT_LENGHT = 177;

    class KeySerializer implements JsonSerializer<Key> {

        @Override
        public JsonElement serialize(Key ident, Type typeOfKey, JsonSerializationContext context) {
            return new JsonPrimitive(KeyFactory.keyToString(ident));
        }
    }

    class TextSerializer implements JsonSerializer<Text> {

        private boolean makeShortText = true;

        public TextSerializer(boolean makeShortText) {
            this.makeShortText = makeShortText;
        }

        @Override
        public JsonElement serialize(Text content, Type typeOfContent, JsonSerializationContext context) {
            StringBuilder result = new StringBuilder(content.getValue().trim());

            if (this.makeShortText) {
                if (result.length() > MAX_JSON_CONTENT_LENGHT) {
                    return new JsonPrimitive(result.substring(0, MAX_JSON_CONTENT_LENGHT) + "...");
                } else {
                    return new JsonPrimitive(result.toString());
                }
            } else {
                return new JsonPrimitive(result.toString());
            }

        }
    }

    class DateSerializer implements JsonSerializer<Date> {

        @Override
        public JsonElement serialize(Date date, Type typeOfSrc, JsonSerializationContext context) {
            return new JsonPrimitive(JSPHelper.getDateStr(date));
        }
    }

    public class EntityUIDJson<T extends BaseEntity> {

        public EntityUIDJson(String operation, T ent) {
            //TODO: dirty hack to avoid stackoverflow in gson
            if (ent != null) {
                this.ent = ent.webSafeClone();

                this.entityPath = ent.getEntityPath();
            }
            this.Ok = operation;
        }
        public String Ok;
        public T ent;
        public Stack<EntityPathElement> entityPath;
    }

    public void printOk(EntityUIDJson uidjson, PrintWriter out) {
        printGson(uidjson, out, true);
    }

    public void printOk(EntityUIDJson uidjson, PrintWriter out, boolean makeShortText) {
        printGson(uidjson, out, makeShortText);
    }

    protected void printGson(Object obj, PrintWriter out, boolean makeShortText) {
        Gson gson = getCustomizedGson(makeShortText);
        String json = gson.toJson(obj);
        out.print(json);
    }

    protected void printGson(Object obj, PrintWriter out) {
        printGson(obj, out, true);//по умолчанию укороченный com.google.appengine.api.datastore.Text
    }

    public void printEntList(List<? extends BaseEntity> list, PrintWriter out) {
        if (list != null) {//TODO: this is dirty hack to avoid stackoverflow problem
            list = getSafeList(list);
        }
        printGson(list, out, true);
    }

    protected abstract void processRequest(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException;

    public static boolean checkParamValue(String paramvalue) {
        return ((paramvalue != null) && (!paramvalue.isEmpty()) && (!paramvalue.equalsIgnoreCase("undefined")));
    }

    public static <E extends BaseEntity> List<E> getSafeList(List<E> val) {
        List<E> result = new ArrayList<E>(val.size());
        for (E t : val) {
            E e = t.webSafeClone();
            result.add(e);
        }
        return result;

    }

    public Gson getCustomizedGson() {
        return getCustomizedGson(true); //по умолчанию укороченный com.google.appengine.api.datastore.Text
    }

    public Gson getCustomizedGson(boolean makeShortText) {

        return new GsonBuilder()
                                .registerTypeAdapter(Key.class, new KeySerializer())
                                .registerTypeAdapter(Text.class, new TextSerializer(makeShortText))
                                .registerTypeAdapter(Date.class, new DateSerializer())
                                .setPrettyPrinting()
                                .create();
    }

    public static Key stringToKey(String encodedKey) {
        return KeyFactory.stringToKey(encodedKey);
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP
     * <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
    // </editor-fold>
}
